using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Collections.ObjectModel;
using Microsoft.Health.PatientConnect;
using Microsoft.Health;
using Microsoft.Health.ItemTypes;
using Microsoft.Health.Web;
using System.Globalization;


namespace DCHelper
{
   
    public static class Functions
    {

        public static string ApplicationId
        {
            get
            {
                if (System.Configuration.ConfigurationManager.AppSettings["ApplicationId"] != null)
                    return System.Configuration.ConfigurationManager.AppSettings["ApplicationId"].ToString();
                
                return "";
            }
        }

        /// <summary>
        /// Create a participant code. A participant can authorize this application by entering this code 
        /// on HealthVault and answering the security question
        /// </summary>
        /// <param name="friendlyName">Participant's Name</param>
        /// <param name="securityQuestion">Security question</param>
        /// <param name="securityAnswer">Security Answer</param>
        /// <param name="applicationPatientId">Application Specific ID for Participant</param>
        /// <returns>Returns 20 digit identity code</returns>
        public static string CreateParticipantIdentityCode(string friendlyName,
                                    string securityQuestion,
                                    string securityAnswer,
                                    string applicationPatientId)
        {
            Guid _applicationId = new Guid(ApplicationId);
            OfflineWebApplicationConnection _offlineConnection = HealthVaultConnectionManager.CreateConnection(_applicationId);
            string _identityCode = string.Empty; 
            _identityCode = PatientConnection.Create(_offlineConnection, friendlyName, securityQuestion, securityAnswer, null, applicationPatientId);
            return _identityCode;
        }


        /// <summary>
        /// Get all the application authorizatons that happend in last n days as specified by the pastDays parameter.
        /// pastDays is set to 0, this function gets ALL the validatations that has happend to date.
        /// </summary>
        /// <param name="pastDays">Specify the last number of days since when the validations needs to be fetched. Specify 0 to fetch all validations</param>
        /// <returns></returns>
        public static Collection<ValidatedPatientConnection> GetValidatedConnectionsInPastDays(int pastDays)
        {
            Guid appId = new Guid(ApplicationId);
            OfflineWebApplicationConnection offlineConnection = HealthVaultConnectionManager.CreateConnection(appId);
            

            if (pastDays > 0)
            {
                DateTime dtSince = DateTime.Now.AddDays(-1 * pastDays);
                return PatientConnection.GetValidatedConnections(offlineConnection, dtSince);
            }

            return PatientConnection.GetValidatedConnections(offlineConnection);
        }



        /// <summary>
        /// Generates an XML Document containing the blood pressure data of participants specified.
        /// Depending on number of participants and date since paramenter, this request could take some time to complete.
        /// </summary>
        /// <param name="dtDateTimeAfter">Specify the date since when blood pressure data is to be downloaded</param>
        /// <param name="participantList">The list of ParticipantConnectionDetails whose blood pressure details need to be downloaded</param>
        /// <returns>XmlDocument containg the participant's data</returns>
        public static XmlDocument GetParticipantData(DateTime dtDateTimeAfter, List<ParticipantConnectionDetails> participantList)
        {
            return ConstructXmlDocument(dtDateTimeAfter, participantList);
        }


        private static XmlDocument ConstructXmlDocument(DateTime dtDateAfter, List<ParticipantConnectionDetails> participantList)
        {

            Guid _applicationId = new Guid(ApplicationId);

            XmlDocument xDoc = new XmlDocument();

            XmlNode declNode = xDoc.CreateNode(XmlNodeType.XmlDeclaration, "", "");
            xDoc.AppendChild(declNode);




            XmlNode xResultNode = xDoc.CreateNode(XmlNodeType.Element, "result", string.Empty);

            //Populate the current query specific attributes 

            XmlNode xQueryNode = xDoc.CreateNode(XmlNodeType.Element, "query", string.Empty);

            XmlNode xQueryWhenNode = xDoc.CreateNode(XmlNodeType.Element, "when", string.Empty);
            xQueryWhenNode.InnerText = DateTime.Now.ToString();
            xQueryNode.AppendChild(xQueryWhenNode);

            XmlNode xQueryCreatedAfterNode = xDoc.CreateNode(XmlNodeType.Element, "created_after", string.Empty);
            xQueryCreatedAfterNode.InnerText = dtDateAfter.ToString();
            xQueryNode.AppendChild(xQueryCreatedAfterNode);


            XmlNode xQueryLoggedInAccountNode = xDoc.CreateNode(XmlNodeType.Element, "loggedin_account", string.Empty);
            xQueryLoggedInAccountNode.InnerText = "application-" + ApplicationId;
            xQueryNode.AppendChild(xQueryLoggedInAccountNode);

            XmlNode xQueryAuthRecordCountNode = xDoc.CreateNode(XmlNodeType.Element, "num_participant_records_fetched", string.Empty);
            xQueryAuthRecordCountNode.InnerText = participantList.Count.ToString();
            xQueryNode.AppendChild(xQueryAuthRecordCountNode);

            xResultNode.AppendChild(xQueryNode);

            XmlNode xUsersNode = xDoc.CreateNode(XmlNodeType.Element, "users", string.Empty);

            
            foreach (ParticipantConnectionDetails participantDetail in participantList)
            {
                Guid personId = participantDetail.PersonId;
                Guid recordId = participantDetail.RecordId;

                HealthRecordAccessor accessor = new HealthRecordAccessor(HealthVaultConnectionManager.CreateConnection(_applicationId, personId), recordId);
                
                XmlNode xUserNode = xDoc.CreateNode(XmlNodeType.Element, "user", string.Empty);
                XmlAttribute xApplicationSpecificIdAttrib = xDoc.CreateAttribute("application_specific_id");
                xApplicationSpecificIdAttrib.Value = participantDetail.ApplicationSpecificId ;
                xUserNode.Attributes.Append(xApplicationSpecificIdAttrib);
                XmlAttribute xNameAttrib = xDoc.CreateAttribute("healthvault_record_name");

                
                //Fetch the Personal and Contact item from HealthVault for this user. 
                //For efficiency, batch the requests 
                Personal personal = null;
                Contact contact = null;

                HealthRecordSearcher searcher_userInfo = new HealthRecordSearcher(accessor);
                
                HealthRecordFilter filter_personal = new HealthRecordFilter();
                filter_personal.TypeIds.Add(Personal.TypeId);
                filter_personal.View.Sections = HealthRecordItemSections.Core | HealthRecordItemSections.Xml;
                searcher_userInfo.Filters.Add(filter_personal);

                HealthRecordFilter filter_contact = new HealthRecordFilter();
                filter_contact.TypeIds.Add(Contact.TypeId);
                filter_contact.View.Sections = HealthRecordItemSections.Core | HealthRecordItemSections.Xml;
                searcher_userInfo.Filters.Add(filter_contact);
               
                ReadOnlyCollection<HealthRecordItemCollection> results_userInfo = searcher_userInfo.GetMatchingItems();

                HealthRecordItemCollection items_personal = results_userInfo[0];
                HealthRecordItemCollection items_contact = results_userInfo[1];
                if (items_personal != null && items_personal.Count > 0)
                {
                    personal = (Personal)items_personal[0];
                }

                if (items_contact != null && items_contact.Count > 0)
                {
                    contact = (Contact)items_contact[0];
                }
                


                //Find the name as in healthvault from the Personal Item of the user
                if (personal != null && personal.Name != null)
                {
                    xNameAttrib.Value = personal.Name.Full;
                }
                else
                {
                    xNameAttrib.Value = "";
                }

                xUserNode.Attributes.Append(xNameAttrib);


                //Find the email as in healthvault from the Contact Item of the user
                if (contact != null)
                {
                    XmlAttribute xEmailAttrib = xDoc.CreateAttribute("email");

                    if (contact.ContactInformation != null &&
                        contact.ContactInformation.PrimaryEmail != null &&
                        contact.ContactInformation.PrimaryEmail.Address != null)
                    {
                        xEmailAttrib.Value = contact.ContactInformation.PrimaryEmail.Address;
                        xUserNode.Attributes.Append(xEmailAttrib);
                    }
                }

                //Finally, Query for the blood pressure readings
                HealthRecordSearcher searcher = new HealthRecordSearcher(accessor);
                HealthRecordFilter filter = new HealthRecordFilter();
                filter.TypeIds.Add(BloodPressure.TypeId);
                filter.CurrentVersionOnly = true;
                filter.EffectiveDateMin = dtDateAfter;
                filter.View.Sections = HealthRecordItemSections.Core | HealthRecordItemSections.Xml;
                searcher.Filters.Add(filter);
                ReadOnlyCollection<HealthRecordItemCollection> results = searcher.GetMatchingItems();
                HealthRecordItemCollection resultCollection = results[0];

                XmlAttribute xReadingCountAttrib = xDoc.CreateAttribute("num_blood_pressure_readings");
                xReadingCountAttrib.Value = resultCollection.Count.ToString();
                xUserNode.Attributes.Append(xReadingCountAttrib);

                //Add the item xml of the blood pressure reading to current user node 
                foreach (HealthRecordItem item in resultCollection)
                {
                    string itemXMLString = item.GetItemXml();
                    xUserNode.InnerXml += itemXMLString;
                }
                xUsersNode.AppendChild(xUserNode);
            }
            xResultNode.AppendChild(xUsersNode);
            xDoc.AppendChild(xResultNode);
            return xDoc;

        }
    }
}
